package sceneInfo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;

import rcscene.Action;
import rcscene.ObjectWeights;
import weka.core.Instance;
import weka.core.Instances;


public class FuzzyScene implements Serializable {

	public static final long serialVersionUID = 2L;
	
	private FuzzyVisualInfo fuzzyVInfo;
	private ArrayList<Action> actions;
	private FuzzyFramework framework;
	private ObjectWeights objWeights; 
	private String teamName = null;
	
	public FuzzyScene(Scene refScene, FuzzyFramework frame, ObjectWeights ow)
	{
	objWeights = ow;
	framework = frame;
	fuzzyVInfo = new FuzzyVisualInfo(framework);
	fuzzyVInfo.setObjectWeights(ow);
	fuzzyVInfo.computeHistograms(refScene.getVision());
	computeOverallHistogram();
	actions = (ArrayList<Action>) refScene.getActions().clone();
	teamName = refScene.getTeamName();
	}
	
	/**
	 * constructor to create a scene with default object weights (1)
	 * @param refScene
	 * @param frame
	 */
	public FuzzyScene(Scene refScene, FuzzyFramework frame)

	{
		this(refScene, frame, new ObjectWeights());
	
	}

	public void computeOverallHistogram(){
		fuzzyVInfo.computeBigHistogram();
	}
	/*
	public Instance toWekaInstance(){
		
		if (fuzzyVInfo.BigHistogram == null){
			computeOverallHistogram(); //see above
		}
		Instance toreturn = new Instance();
		for (int val : fuzzyVInfo.BigHistogram){
			
		}
		
		return null;
	}*/
	
	
/**
 * computes Jaccard Histogram Coefficient with another FuzzyScene
 * (Similarity metric)
 * 
 * @param ftwo another fuzzy scene to compare with
 * @param weights weights for the differetn object types
 * @return the Jaccard coefficient weighted by the weights. Maximum similarity is 100 * the sum of the weights, minimum similarity is 0 if nothing in the two scenes overlaps
 * 
 */
public float JaccardSimilarity(FuzzyScene ftwo, ObjectWeights weights) {
		
		int[] hist1 = getFuzzyVInfo().BigHistogram;
		int[] hist2 = ftwo.getFuzzyVInfo().BigHistogram;
		int smalldim = framework.alphanumber*framework.distnumber; //dimension of each object histogram
		
		if ((hist1.length != hist2.length)|| (hist1.length != 7*smalldim)){
				//throw InvalidParameterException("Error : Euclidian Distance : the histograms have different dimensions");
				return 99999;
			}
		
		// calculate the jaccard coefficient of two histograms=================
		// first get all the objectHistograms
		 ObjectHistogram ballHist1 = getFuzzyVInfo().getBallHist();
		 ObjectHistogram teammateHist1 = getFuzzyVInfo().getTeammateHist();
		 ObjectHistogram opponentHist1 = getFuzzyVInfo().getOpponentHist();
		 ObjectHistogram unknownPlayerHist1 = getFuzzyVInfo().getUnknownPlayerHist();
		 ObjectHistogram goalHist1 = getFuzzyVInfo().getGoalHist();
		 ObjectHistogram flagHist1 = getFuzzyVInfo().getFlagHist();
		 ObjectHistogram lineHist1 = getFuzzyVInfo().getLineHist();
		
		 ObjectHistogram ballHist2 = ftwo.getFuzzyVInfo().getBallHist();
		 ObjectHistogram teammateHist2 = ftwo.getFuzzyVInfo().getTeammateHist();
		 ObjectHistogram opponentHist2 = ftwo.getFuzzyVInfo().getOpponentHist();
		 ObjectHistogram unknownPlayerHist2 = ftwo.getFuzzyVInfo().getUnknownPlayerHist();
		 ObjectHistogram goalHist2 = ftwo.getFuzzyVInfo().getGoalHist();
		 ObjectHistogram flagHist2 = ftwo.getFuzzyVInfo().getFlagHist();
		 ObjectHistogram lineHist2 = ftwo.getFuzzyVInfo().getLineHist();

		 int inter=0 , union=0, sum=0;//, w=1;
		 
		float result =0;
		
		/*
		 * compute weighted sum of histogram distances
		 * the distance is computed separately for
		 * each Object histogram,(ie the histogram for each object category) 
		 * and the result is weighted with the appropriate objectweight element
		 */
		
		
		if (weights.getBallWeight()>0){
			if ((ballHist1.getSize()>0)&&(ballHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(ballHist1.getHistogram(i), ballHist2.getHistogram(i));
					union += Math.max(ballHist1.getHistogram(i), ballHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getBallWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((ballHist1.getSize()==0)&&(ballHist2.getSize()==0))
			{result += 100*weights.getBallWeight();}//both 0 so perfect match 
		}
		
		// distance between teammate player histograms--
		if (weights.getTeamPlayerWeight()>0){
			if ((teammateHist1.getSize()>0)&&(teammateHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(teammateHist1.getHistogram(i), teammateHist2.getHistogram(i));
					union += Math.max(teammateHist1.getHistogram(i), teammateHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getTeamPlayerWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((teammateHist1.getSize()==0)&&(teammateHist2.getSize()==0))
			{result += 100*weights.getTeamPlayerWeight();}//both 0 so perfect match
		}
		
		// distance between opponent player histograms--
		if (weights.getOpponentPlayerWeight()>0){
			if ((opponentHist1.getSize()>0)&&(opponentHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(opponentHist1.getHistogram(i), opponentHist2.getHistogram(i));
					union += Math.max(opponentHist1.getHistogram(i), opponentHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getOpponentPlayerWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((opponentHist1.getSize()==0)&&(opponentHist2.getSize()==0))
			{result += 100*weights.getOpponentPlayerWeight();}//both 0 so perfect match
		}
		
		// distance between unknown player histograms--
		if (weights.getUnknownPlayerWeight()>0){
			if ((unknownPlayerHist1.getSize()>0)&&(unknownPlayerHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(unknownPlayerHist1.getHistogram(i), unknownPlayerHist2.getHistogram(i));
					union += Math.max(unknownPlayerHist1.getHistogram(i), unknownPlayerHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getUnknownPlayerWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((unknownPlayerHist1.getSize()==0)&&(unknownPlayerHist2.getSize()==0))
			{result += 100*weights.getUnknownPlayerWeight();}//both 0 so perfect match
		}
		
		// distance between goal histograms--
		if (weights.getGoalWeight()>0){
			if ((goalHist1.getSize()>0)&&(goalHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(goalHist1.getHistogram(i), goalHist2.getHistogram(i));
					union += Math.max(goalHist1.getHistogram(i), goalHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getGoalWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((goalHist1.getSize()==0)&&(goalHist2.getSize()==0))
			{result += 100*weights.getGoalWeight();}//both 0 so perfect match
		}
		
	  	// distance between Flag histograms--
		if (weights.getFlagWeight()>0){
			if ((flagHist1.getSize()>0)&&(flagHist2.getSize()>0)){
			
				for (int i=0; i<smalldim;i++){
					inter += Math.min(flagHist1.getHistogram(i), flagHist2.getHistogram(i));
					union += Math.max(flagHist1.getHistogram(i), flagHist2.getHistogram(i));
				}
				sum = inter*100/union;
				result += sum*weights.getFlagWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((flagHist1.getSize()==0)&&(flagHist2.getSize()==0))
			{result += 100*weights.getFlagWeight();}//both 0 so perfect matchif (weights.getOpponentPlayerWeight() > 0) {
		}
	  	
		if (weights.getLinesWeight() > 0) {
	  	// distance between Line histograms--
			if ((lineHist1.getSize()>0)&&(lineHist2.getSize()>0)){
				
				for (int i=0; i<smalldim;i++){
					inter += Math.min(lineHist1.getHistogram(i), lineHist2.getHistogram(i));
					union += Math.max(lineHist1.getHistogram(i), lineHist2.getHistogram(i));
				}
				sum = inter*100/union; // union is non-zero
				result += sum*weights.getLinesWeight();
				inter=0;
				union =0;
				sum=0;
			}
		else if ((lineHist1.getSize()==0)&& (lineHist2.getSize()==0))
			{result += 100*weights.getLinesWeight();}//both 0 so perfect match
		}
			return result;		
	}
	
	/**Fuzzy Euclidian distance to other FuzzyScene, using weights for the difference object types
	 * 
	 */
	public float EuclidianDistanceTo(FuzzyScene ftwo, ObjectWeights weights) {
		
		if (!(ftwo instanceof sceneInfo.FuzzyScene)) {
			//throw InvalidParameterException("Error: Euclidian dist : the scenes are not fuzzy scenes");
			// to do: define real exceptions
			return 999999;
		}
		int[] hist1 = this.getFuzzyVInfo().BigHistogram;
		int[] hist2 = ftwo.getFuzzyVInfo().BigHistogram;
		int smalldim = framework.alphanumber*framework.distnumber; //dimension of each object histogram
		
		if ((hist1.length != hist2.length)|| (hist1.length != 7*smalldim)){
				//throw InvalidParameterException("Error : Euclidian Distance : the histograms have different dimensions");
				return 99999;
			}
		
		// calculate the euclidian distance between two histograms=================
		// first get all the objectHistograms
		 ObjectHistogram ballHist1 = getFuzzyVInfo().getBallHist();
		 ObjectHistogram teammateHist1 = getFuzzyVInfo().getTeammateHist();
		 ObjectHistogram opponentHist1 = getFuzzyVInfo().getOpponentHist();
		 ObjectHistogram unknownPlayerHist1 = getFuzzyVInfo().getUnknownPlayerHist();
		 ObjectHistogram goalHist1 = getFuzzyVInfo().getGoalHist();
		 ObjectHistogram flagHist1 = getFuzzyVInfo().getFlagHist();
		 ObjectHistogram lineHist1 = getFuzzyVInfo().getLineHist();
		
		 ObjectHistogram ballHist2 = ftwo.getFuzzyVInfo().getBallHist();
		 ObjectHistogram teammateHist2 = ftwo.getFuzzyVInfo().getTeammateHist();
		 ObjectHistogram opponentHist2 = ftwo.getFuzzyVInfo().getOpponentHist();
		 ObjectHistogram unknownPlayerHist2 = ftwo.getFuzzyVInfo().getUnknownPlayerHist();
		 ObjectHistogram goalHist2 = ftwo.getFuzzyVInfo().getGoalHist();
		 ObjectHistogram flagHist2 = ftwo.getFuzzyVInfo().getFlagHist();
		 ObjectHistogram lineHist2 = ftwo.getFuzzyVInfo().getLineHist();

		 int diff=0 , sum=0, w=1;
		 
		float result =0;
		
		/*
		 * compute weighted sum of histogram distances
		 * the distance is computed separately for
		 * each Object histogram,(ie the histogram for each object category) 
		 * and the result is weighted with the appropriate objectweight element
		 */
		
		if (weights.getBallWeight() > 0) {
		// distance between ball histograms--
		  	for (int i=0; i<smalldim;i++){
				diff= ballHist1.getHistogram(i)- ballHist2.getHistogram(i);
				sum += diff *diff;	
			}
		result += (float)Math.sqrt(sum)*weights.getBallWeight();
		sum=0;
		}
		
		if (weights.getTeamPlayerWeight() > 0) {
		// distance between teammate player histograms--
		 for (int i=0; i<smalldim;i++){
				diff= teammateHist1.getHistogram(i)-teammateHist2.getHistogram(i);
				sum += diff *diff;	//sum of squares
			}
		result += (float)Math.sqrt(sum)*weights.getTeamPlayerWeight(); //add weighted distance to final result
		sum=0;
	    }
		
		// distance between opponent player histograms--
		if (weights.getOpponentPlayerWeight() > 0) {
		for (int i=0; i<smalldim;i++){
			diff= opponentHist1.getHistogram(i)-opponentHist2.getHistogram(i);
			sum += diff *diff;	
		}
	  	result += (float)Math.sqrt(sum)*weights.getOpponentPlayerWeight() ;
	  	sum=0;
		}

		// distance between unknown player histograms--
		if (weights.getUnknownPlayerWeight() > 0) {
		for (int i=0; i<smalldim;i++){
			diff= unknownPlayerHist1.getHistogram(i)-unknownPlayerHist2.getHistogram(i);
			sum += diff *diff;	
		}
    	result += (float)Math.sqrt(sum)*weights.getUnknownPlayerWeight();
    	sum=0;
		}
    	
		// distance between goal histograms--
		if (weights.getGoalWeight() > 0) {
		for (int i=0; i<smalldim;i++){
			diff= goalHist1.getHistogram(i)-goalHist2.getHistogram(i);
			sum += diff *diff;	
		}
	  	result += (float)Math.sqrt(sum)*weights.getGoalWeight();
		sum=0;
		}
	  	// distance between Flag histograms--
	  	if (weights.getFlagWeight() > 0) {
	  	for (int i=0; i<smalldim;i++){
			diff= flagHist1.getHistogram(i)- flagHist2.getHistogram(i);
			sum += diff *diff;	
		}
	  	result += (float)Math.sqrt(sum)*weights.getFlagWeight();
	  	sum=0;
	  	}
	  	
		if (weights.getLinesWeight() > 0) {
	  	// distance between Line histograms--
	  	for (int i=0; i<smalldim;i++){
			diff= lineHist1.getHistogram(i)-lineHist2.getHistogram(i);
			sum += diff *diff;	
		}
	  	result += (float)Math.sqrt(sum)*weights.getLinesWeight();
	  	//sum=0; not necessary
		}

		return result;
	}
	
	public String getTeamName(){
		return teamName;
	}
	
	public FuzzyVisualInfo getFuzzyVInfo(){
		return fuzzyVInfo;
	}
	
	public ArrayList<Action> getActions()
	{
		return actions;
	}

	/**
	 * creates a weka isntance object from the fuzzy scene. Provides the histogram 
	 * values (non categorical attributes) , and if there is an associated action, 
	 * als includes the action, which is the class (categorical) attribute.
	 * @return
	 */
	public Instance toWekaInstance() {
		
		int datasize =fuzzyVInfo.BigHistogram.length;
		
		
		double [] values;
		if (actions.size()==0) //scenes used for trinaing classifiers will have actions; scenes discretized 
			values = new double [datasize];
		else
			values = new double [datasize+3];
		
		for (int i =0;i<datasize; i++)
			values[i]=(double)fuzzyVInfo.BigHistogram[i];
		
		if (actions.size()>0){ // if there is an action then we can add it. Otherwise it will be a scene "to be classified" !
			values[datasize] = (double) actions.get(0).getAction(); // int value encoding the action
			values[datasize+1] = (double) actions.get(0).getActionPower();
			values[datasize+2] = (double) actions.get(0).getActionDirection();
		}
		
		Instance toReturn = new Instance(1, values); //1 is for the weight of the instance... default value. values are the attribute values
		
		return toReturn;
	}
	
	/*maybe later
	 * 
	 * protected String outputCell(int row, int column)
	{
		String x = new String();
		Vector stuff = getObjectsAt(column, row);

		// output format is: 2 dig for ball, 2 for goal, 3 for teammates, the rest for later
		x = x.concat(fuzzyVInfo.BigHistogram[number] );
		x = x.concat( getGoalCount(stuff) > 0 ? "G " : "  ");

		int count = getPlayerCount(stuff);
		x = x.concat( count > 0 ? count + "P" : "  ");
		count = getFlagCount(stuff);
		x = x.concat( count > 0 ? count + "F" : "  ");
		count = getLineCount(stuff);
		x = x.concat( count > 0 ? count + "L" : "  ");
		
		return x;
	}
	private String outputRowMarkings()
	{
		String x = new String();
		for(int i = 0; i < tableColumns; i++)
		{
			x = x.concat("+----------");
		}
		x = x.concat("+\n");
		return x;
	}**/
	
}
